<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>正则表达式 - JavaScript</title>
    <style>

    </style>
</head>
<body>
    <h1>正则表达式</h1>
    <p>在编写处理字符串的程序或网页时，经常会有查找符合某些复杂规则的字符串的需要。</p>
    <p>正则表达式就是用于描述这些规则的工具，换句话说，正则表达式就是记录文本规则的代码。 </p>
    <p>正则表达式并非是JavaScript特有的，只要语言支持正则表达式，均可以使用。</p>

    <h4>学习目标</h4>
    <ol>
        <li>熟悉常见的匹配元字符、限定符等</li>
        <li>熟悉常见的匹配场景，如手机号、邮箱等</li>
        <li>熟悉RegExp对象</li>
    </ol>

    <script type="text/javascript">

        // -----------------------------
        // -- 0. 前奏
        // -----------------------------
        // 0.1 设计一个用户名输入框，用户名只允许英文字符，大小写均可，长度8~15
        //      填写完成后对用户名进行验证。
        // 0.2 正则表达式其他还有什么用处？
        // 0.3 正则表达式调试工具：https://regexr-cn.com/
        // 0.4 熟悉JavaScript中的正则表达式的使用。


        // -----------------------------
        // 1. 元字符
        // -----------------------------
        /*
            常用方法：
            语法：
                . 	匹配除换行符以外的任意字符
                \w 	匹配字母或数字或下划线或汉字
                \s 	匹配任意的空白符
                \d 	匹配数字
                \b 	匹配单词的开始或结束
                ^ 	匹配字符串的开始
                $ 	匹配字符串的结束
         */
        // 1.1 设计一个用户名输入框，用户名只允许英文字符，大小写均可，长度8~15
        //      填写完成后使用正则表达式对用户名进行验证。
        // 1.2 验证一个字符串是否是手机号码。
        //      移动：134、135、136、137、138、139、147、150、151、152、157、158、
        //          159、182、187、188。其中：147、182、187、188为3G时分配。
        //      联通：130、131、132、155、156、185、186（WCDMA)
        //      电信：133、153、180、189（CDMA2000）
        // 1.3 英文语句单词之间一般一个空格，格式化下面的英文语句，删除多余的空格。
        //      Dream  is not about   what you want , but   what you  do after  knowing who you are .
        //      理想不是想想而已，是看清自我后的不顾一切。


        // -----------------------------
        // 2. 重复符号
        // -----------------------------
        /*
            匹配字符出现若干次

            语法：
                * 	重复零次或更多次
                + 	重复一次或更多次
                ? 	重复零次或一次
                {n} 	重复n次
                {n,} 	重复n次或更多次
                {n,m} 	重复n到m次
         */
        //
        // 2.1 对第1节的的例子进行优化，使用重复符号。


        // -----------------------------
        // 3. 字符转义
        // -----------------------------
        /*
            如果你想查找元字符本身的话，比如你查找.,或者*,就出现了问题：
            你没办法指定它们，因为它们会被解释成别的意思。
            这时你就得使用\来取消这些字符的特殊意义。
            因此，你应该使用\.和\*。当然，要查找\本身，你也得用\\。
         */
        // 3.1 匹配1个字符串是否是一个域名，
        //  域名规则：
        //      a. 只提供英文字母(a-z，不区分大小写)、数字(0-9)、以及"-"(英文中的连词号，即中横线)。
        //      b. "-"不能用作开头和结尾。
        //      c. 长度不能超过63个字符。


        // -----------------------------
        // 4. 反义
        // -----------------------------
        /*
            有时需要查找不属于某个能简单定义的字符类的字符。
            比如想查找除了数字以外，其它任意字符都行的情况，这时需要用到反义。

            字符：
                \W 	匹配任意不是字母，数字，下划线，汉字的字符
                \S 	匹配任意不是空白符的字符
                \D 	匹配任意非数字的字符
                \B 	匹配不是单词开头或结束的位置
                [^x] 	匹配除了x以外的任意字符
                [^aeiou] 	匹配除了aeiou这几个字母以外的任意字符
         */


        // -----------------------------
        // 5. 分支条件
        // -----------------------------
        /*
            正则表达式里的分枝条件指的是有几种规则，如果满足其中任意一种规则都应该当成匹配，
            具体方法是用 | 把不同的规则分隔开。
         */
        // 5.1 匹配两种以连字号分隔的电话号码：
        //      一种是三位区号，8位本地号(如010-12345678)，
        //      一种是4位区号，7位本地号(0376-2233445)。



        // -----------------------------
        // 6. 子表达式
        // -----------------------------
        /*
            我们已经提到了怎么重复单个字符（直接在字符后面加上限定符就行了）；
            但如果想要重复多个字符又该怎么办？
            你可以用小括号来指定子表达式(也叫做分组)，
            然后你就可以指定这个子表达式的重复次数了，
            你也可以对子表达式进行其它一些操作(后面会有介绍)。

            语法:
                (子表达式){n} // 表示符合 子表达式 重复 n 次
         */
        // 6.1 匹配ip地址，ip地址形如: 8.8.8.8, 192.168.1.119



        // -----------------------------
        // 7. 子表达式 后向引用
        // -----------------------------
        /*
            使用小括号指定一个子表达式后，
            匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。
            默认情况下，每个分组会自动拥有一个组号，规则是：
            从左向右，以分组的左括号为标志，第一个出现的分组的组号为1，第二个为2，以此类推。

            语法：
                (exp) 	        // 匹配exp,并捕获文本到自动命名的组里
                (?<name>exp) 	// 匹配exp,并捕获文本到名称为name的组里，也可以写成(?'name'exp)
                (?:exp) 	    // 匹配exp,不捕获匹配的文本，也不给此分组分配组号
         */
        // 7.1 匹配如下字符串的标签名： <h1>javascript中的正则表达式</h1>



        // -----------------------------
        // 8. 零宽断言（高能预警）
        // -----------------------------
        /*
            用于查找在某些内容(但并不包括这些内容)之前或之后的东西，
            也就是说它们像\b,^,$那样用于指定一个位置，
            这个位置应该满足一定的条件(即断言)，因此它们也被称为零宽断言。

            语法：
                (?=exp) 	// 匹配exp前面的位置, 零宽度正预测先行断言
                (?<=exp) 	// 匹配exp后面的位置, 零宽度正回顾后发断言

         */
        // 8.1 匹配: I'm singing while you're dancing.
        //      以ing结尾的单词的前面部分(除了ing以外的部分)
        // 8.2 匹配: reading a book
        //      匹配以re开头的单词的后半部分(除了re以外的部分)



        // -----------------------------
        // 9. 负向零宽断言（高能预警）
        // -----------------------------
        /*
            负向零宽断言能解决这样的问题，因为它只匹配一个位置，并不消费任何字符。

            语法：
                (?!exp) 	// 匹配后面跟的不是exp的位置
                (?<!exp) 	// 匹配前面不是exp的位置
         */
        // 9.1 匹配包含后面不是字母u的字母q的单词: iraq、queue、question、qq



        // -----------------------------
        // 10. 贪婪与懒惰
        // -----------------------------
        /*
            以a开始，以b结束的字符串。如果用它来搜索aabab的话，它会匹配整个字符串aabab。这被称为贪婪匹配。
            有时，我们更需要懒惰匹配，也就是匹配尽可能少的字符。
            前面给出的限定符都可以被转化为懒惰匹配模式，只要在它后面加上一个问号?。
            这样.*?就意味着匹配任意数量的重复，但是在能使整个匹配成功的前提下使用最少的重复。

            语法：
                *? 	    // 重复任意次，但尽可能少重复
                +? 	    // 重复1次或更多次，但尽可能少重复
                ?? 	    // 重复0次或1次，但尽可能少重复
                {n,m}? 	// 重复n到m次，但尽可能少重复
                {n,}? 	// 重复n次以上，但尽可能少重复
         */


        // -----------------------------
        // 11. 其他常用符号
        // -----------------------------
        /*
            用于查找在某些内容(但并不包括这些内容)之前或之后的东西，
            也就是说它们像\b,^,$那样用于指定一个位置，
            这个位置应该满足一定的条件(即断言)，因此它们也被称为零宽断言。

            语法：
                \t 	制表符，Tab
                \r 	回车
                \n 	换行符
         */
        // 11.1 使用数组保存班级所有同学，然后遍历打印。



        // ----------------------------------------------------
        // -- 练习
        // ----------------------------------------------------
        // 1. 匹配qq_nav.html所有的a标签，打印链接名字，链接地址。


    </script>
</body>
</html>